package edu.mapi.ir.viewer;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.net.SocketException;
import java.util.Vector;
import java.util.prefs.Preferences;

import javax.swing.AbstractAction;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;

import edu.mapi.ir.gui.AudioClips;
import edu.mapi.ir.gui.GuiUtils;
import edu.mapi.ir.gui.WaitPanel;
import edu.mapi.ir.log.LogReplay;
import edu.mapi.ir.log.ReplayPanel;
import edu.mapi.ir.viewer.comm.MessageListener;
import edu.mapi.ir.viewer.comm.ViewerComms;
import foxtrot.AsyncTask;
import foxtrot.AsyncWorker;

/**
 * @author ZP
 */
public class MazeViewer extends JFrame implements MessageListener {

	private Maze maze = null;
	private Vector<GridPosition> grid = null;	
	private Preferences prefs = Preferences.systemNodeForPackage(MazeViewer.class);
	private String host = prefs.get("host", "127.0.0.1");
	private MazePanel mazePanel = new MazePanel();
	private JPanel mainPanel;
	private IntroPanel introPanel = new IntroPanel();
	private Component defaultGlassPane = getGlassPane();
	private ViewerComms comms;
	private ScoreWall scores = new ScoreWall();	
	private AbstractAction connect, reset, showGrid, showPaths, showBeaconVis, start, stop, replay;
	private ReplayPanel replayPanel = null;
	private LogReplay logReplay;
	
	public MazeViewer() {
		createMenus();		
		setTitle("Maze Viewer");		
		setLayout(new BorderLayout(2,2));
		add(introPanel, BorderLayout.CENTER);
	}
	
	private void createMenus() {
		JMenuBar menubar = new JMenuBar();
		
		JMenu file = new JMenu("File");
		
		connect = new AbstractAction("Connect...", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				String input = JOptionPane.showInputDialog(null, "Please provide the server hostname", "127.0.0.1");				
				if (input != null) {
					
					host = input;
					prefs.put("hostname", input);
					
					WaitPanel wp = new WaitPanel();
					setGlassPane(wp);
					wp.setVisible(true);
					AudioClips.radio.play();
					setEnabled(false);
					AsyncWorker.post(new AsyncTask() {
						
						public Object run() throws Exception {
							
							reset.actionPerformed(null);
							
							if (comms != null)
								comms.disconnect();
							comms = new ViewerComms();
							comms.connect(host, 6000);
							comms.addListener(MazeViewer.this);
							if (comms.getGridXML() == null) {
								throw new SocketException("Unable to connect to server on port "+comms.getServerPort());
							}
							grid = GridPosition.readString(comms.getGridXML());
							maze = Maze.readString(comms.getLabXML());
							maze.setGrid(grid);
							if (scores != null)
								scores.reset();
							
							scores = new ScoreWall();
							if (introPanel != null) {
								remove(introPanel);
								introPanel = null;
								mainPanel = new JPanel(new BorderLayout(0,0));
								mainPanel.setBackground(Color.black);
								mainPanel.add(mazePanel, BorderLayout.CENTER);
								add(mainPanel, BorderLayout.CENTER);
								
								mainPanel.add(scores, BorderLayout.NORTH);
								mazePanel.revalidate();								
							}
							mazePanel.clearMice();
							mazePanel.setMaze(maze);
							
							return null;
						}
						
						protected void finish() {
							try {
								AudioClips.radio.stop();
								getResultOrThrow();
								AudioClips.r2d2a.play();
								
								start.setEnabled(true);
								stop.setEnabled(true);
								showGrid.setEnabled(true);
								showBeaconVis.setEnabled(true);
								showPaths.setEnabled(true);
								reset.setEnabled(true);
								replay.setEnabled(false);
								//createReplay.setEnabled(false);
							}
							catch (Exception ex) {
								GuiUtils.errorMessage(MazeViewer.this, "Error connecting to server", ex.getClass().getSimpleName()+"("+ex.getMessage()+")");
								ex.printStackTrace();
							}
							finally {
																
								setGlassPane(defaultGlassPane);
								setEnabled(true);								
							}
						}
						
						@Override
						public void failure(Throwable arg0) {
							
						}
						
						@Override
						public void success(Object arg0) {
							
							
						}
					});
				}
			}
		};		
		JMenuItem item = file.add(connect);		
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK));
		
		reset = new AbstractAction("Reset", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				if (replayPanel!=null && replayPanel.isVisible()) {
					replayPanel.stop.actionPerformed(null);					
					remove(replayPanel);
				}
					
				
				if (introPanel == null)
					introPanel = new IntroPanel();
				
				
				
				if (comms != null && comms.isConnected()) {
					comms.disconnect();
					comms = null;
				}
				if (mainPanel != null)
					remove(mainPanel);
				
				
				
				add(introPanel, BorderLayout.CENTER);
				introPanel.revalidate();
				scores.reset();
				
				start.setEnabled(false);
				stop.setEnabled(false);
				showGrid.setEnabled(false);
				showBeaconVis.setEnabled(false);
				showPaths.setEnabled(false);
				reset.setEnabled(true);
				replay.setEnabled(true);
				connect.setEnabled(true);
				
			}
		};
		
		item = file.add(reset);
		reset.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK));
		

		file.addSeparator();
		
		replay = new AbstractAction("Replay Log") {
			public void actionPerformed(ActionEvent e) {
				JFileChooser chooser = new JFileChooser(new File(".", "logs"));
				int resp = chooser.showOpenDialog(mazePanel);
				if (resp == JFileChooser.APPROVE_OPTION) {
					File f = chooser.getSelectedFile();
					logReplay = LogReplay.parseLog(f.getAbsolutePath());
					
					try {
						grid = GridPosition.readString(logReplay.getGridXML());						
						maze = Maze.readString(logReplay.getLabXML());
						maze.setGrid(grid);
						if (scores != null)
							scores.reset();
						
						scores = new ScoreWall();
						if (introPanel != null) {
							remove(introPanel);
							introPanel = null;
							mainPanel = new JPanel(new BorderLayout(0,0));
							mainPanel.setBackground(Color.black);
							mainPanel.add(mazePanel, BorderLayout.CENTER);
							add(mainPanel, BorderLayout.CENTER);						
							mainPanel.add(scores, BorderLayout.NORTH);
							mazePanel.revalidate();													
							mazePanel.clearMice();
							mazePanel.setMaze(maze);							
						}
						
						replayPanel = new ReplayPanel(logReplay, mazePanel, scores);
						add(replayPanel, BorderLayout.SOUTH);
						start.setEnabled(false);
						stop.setEnabled(false);
						showGrid.setEnabled(true);
						showBeaconVis.setEnabled(true);
						showPaths.setEnabled(true);
						reset.setEnabled(true);
						//createReplay.setEnabled(true);
					}
					catch (Exception ex) {
						ex.printStackTrace();
					}
				}
			}
		};
		item = file.add(replay);		
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.ALT_MASK));
		
//		createReplay = new AbstractAction("Create Replay Package") {
//			public void actionPerformed(ActionEvent e) {
//				
//			}
//		};
//		
		file.addSeparator();
		
		item = file.add(new AbstractAction("Exit", GuiUtils.getIcon("imgs/exit.png")) {
			public void actionPerformed(ActionEvent e) {
				System.exit(0);
			}
		});		
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.ALT_MASK));
		
		menubar.add(file);
		
		JMenu view = new JMenu("View");
		
		showGrid = new AbstractAction("Grid", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				if (mazePanel != null)
					mazePanel.setGridEnabled(!mazePanel.isGridEnabled());
			}
		};
		
		item = view.add(showGrid);
		showGrid.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_G, InputEvent.ALT_MASK));
		

		showBeaconVis = new AbstractAction("Beacon Visibility", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				if (mazePanel != null)
					mazePanel.setBeaconVisEnabled(!mazePanel.isBeaconVisEnabled());
			}
		};
		
		item = view.add(showBeaconVis);
		showBeaconVis.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, InputEvent.ALT_MASK));
		
		
		showPaths = new AbstractAction("Mouse Paths", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				if (mazePanel != null)
					mazePanel.setPathsVisible(!mazePanel.isPathsVisible());
			}
		};
		
		item = view.add(showPaths);
		showPaths.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.ALT_MASK));
		
		menubar.add(view);
		
		view.addSeparator();
		
		JMenu theme = new JMenu("Set Theme");
		
		for (String t : Theme.THEMES) {
			final String th = t;
			AbstractAction setTheme = new AbstractAction(t) {
				public void actionPerformed(ActionEvent e) {
					Theme.setCurrentTheme(th);
					mazePanel.setMaze(maze);
				}
			};
			theme.add(setTheme);
		}
		
		view.add(theme);
		
		JMenu commands = new JMenu("Command");
		
		start = new AbstractAction("Start", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				comms.sendToServer("<Start/>");
				AudioClips.r2d2c.play();
			}
		};
		
		item = commands.add(start);
		start.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_MASK));
		

		stop = new AbstractAction("Stop", GuiUtils.getIcon("imgs/start.png")) {
			public void actionPerformed(ActionEvent e) {
				comms.sendToServer("<Stop/>");
				AudioClips.r2d2b.play();
			}
		};
		
		item = commands.add(stop);
		stop.setEnabled(false);
		item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
		
		
		
		menubar.add(commands);
		
		setJMenuBar(menubar);
	}
	
	public void robotUpdated(MousePlayer mouse) {
		mazePanel.setMouse(mouse);
		scores.setMouse(mouse);
	}
	
	public void ghostUpdated(MousePlayer mouse) {
		mazePanel.setMouse(mouse);
	}
	
	public static void main(String[] args) {
		
		try
		{
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());			
		}
		catch(Exception e){
		}
		MazeViewer app = new MazeViewer();
		app.setIconImage(GuiUtils.getImage("imgs/r2d2.png"));
		app.setSize(700, 530);
		GuiUtils.centerOnScreen(app);
		app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		app.setVisible(true);
	}

	public MazePanel getMazePanel() {
		return mazePanel;
	}

}
